﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace Tippelde.Web.Helpers
{
    public enum DateCompareType
    {
        Equals, 
        LessThan,
        GreaterThan
    }

    public enum DateCompareUnit
    {
        DateTime,
        DateOnly,
        TimeOnly
    }
    
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
    public class DateCompareAttribute : ValidationAttribute
    {
        string otherPropertyName;
        public DateCompareUnit Unit { get; set; }
        public DateCompareType Type { get; set; }

        public DateCompareAttribute(string otherPropertyName, string errorMessage)
            : base()
        {
            this.otherPropertyName = otherPropertyName;
        }


        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ValidationResult validationResult = ValidationResult.Success;
            try
            {
                // Using reflection we can get a reference to the other date property, in this example the project start date
                var otherPropertyInfo = validationContext.ObjectType.GetProperty(this.otherPropertyName);
                // Let's check that otherProperty is of type DateTime as we expect it to be
                if (otherPropertyInfo.PropertyType.Equals(typeof(DateTime)) || otherPropertyInfo.PropertyType.Equals(typeof(DateTime?)))
                {
                    DateTime? toValidate = (DateTime?)value;
                    DateTime? referenceProperty = (DateTime?)otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);
                    
                    switch(Unit)
                    {
                        case DateCompareUnit.DateOnly:
                            if(toValidate.HasValue) 
                                toValidate = toValidate.Value.Date;
                            if(referenceProperty.HasValue) 
                                referenceProperty = referenceProperty.Value.Date;
                            break;
                        case DateCompareUnit.TimeOnly:
                            if(toValidate.HasValue) 
                                toValidate = DateTime.Now.Date.Add(toValidate.Value.TimeOfDay);
                            if(referenceProperty.HasValue) 
                                referenceProperty = DateTime.Now.Date.Add(referenceProperty.Value.TimeOfDay);
                            break;
                        default: break;

                    }
                    // if the end date is lower than the start date, than the validationResult will be set to false and return
                    // a properly formatted error message
                    if(toValidate.HasValue && referenceProperty.HasValue){
                        if (Type == DateCompareType.GreaterThan && toValidate.Value.CompareTo(referenceProperty.Value) < 1)
                        {
                            validationResult = new ValidationResult(ErrorMessageString);
                        }
                        else if (Type == DateCompareType.LessThan && toValidate.Value.CompareTo(referenceProperty.Value) > -1)
                        {
                            validationResult = new ValidationResult(ErrorMessageString);
                        }
                        else if (Type == DateCompareType.Equals && toValidate.Value.CompareTo(referenceProperty.Value) != 0)
                        {
                            validationResult = new ValidationResult(ErrorMessageString);
                        }
                    }
                }
                else
                {
                    validationResult = new ValidationResult("An error occurred while validating the property. OtherProperty is not of type DateTime?");
                }
            }
            catch (Exception ex)
            {
                // Do stuff, i.e. log the exception
                // Let it go through the upper levels, something bad happened
                throw ex;
            }

            return validationResult;
        }
    }
}